#include "SdkPwm.h"
#include "InCommon.h"

Com_s64 g_ChipSdk_Class_Pwm_Period = 0;

int SdkPwm_Open(int device_no)
{
    int fd = -1;
    int ret = 0;
    char pwm_name[8] = {0};
    char dev_name[64] = {0};
    char path[64] = {0};

    sprintf(path, "/sys/class/pwm/pwmchip0/pwm%d", device_no);
    if (!access(path, F_OK))
    {
        printf( "pwm %d already opened.\n", device_no);
        return 0;
    }

    sprintf(dev_name, "/sys/class/pwm/pwmchip0/export");
    fd = open(dev_name, O_WRONLY);
    if (fd < 0)
    {
        printf("Open pwmchip0 fail\n");
        return -1;
    }

    sprintf(pwm_name, "%d",device_no);
    ret = write(fd, pwm_name, strlen(pwm_name));
    if(ret < 0)
    {
        close(fd);
        printf("create pwm %d fail\n", device_no);
        return -1;
    }
    close(fd);

    return 0;
}

int SdkPwm_Set(int device_no, long long duty_ns, long long period_ns)
{
    int fd = -1;
    int ret;
    char path[64] = {0};
    char str[32] = {0};

    sprintf(path, "/sys/class/pwm/pwmchip0/pwm%d", device_no);
    if (access(path, F_OK))
    {
        printf("pwm dev %d not open.\n", device_no);
        return -1;
    }

    /*
    *disable pwm before set pwm period and duty_cycle
    */
    memset(path, 0, 64);
    sprintf(path, "/sys/class/pwm/pwmchip0/pwm%d/enable", device_no);
    fd = open(path, O_RDWR);
    if (fd < 0)
    {
        printf("pwm dev %d enable file open failed.\n", device_no);
        return -1;
    }

    ret = write(fd, "0", strlen("0"));
    if (ret < 0)
    {
        printf("pwm dev %d set disable failed.\n", device_no);
        close(fd);
        return -1;
    }
    close(fd);

    /*
    *set pwn period
    */
    memset(path, 0, 64);
    sprintf(path, "/sys/class/pwm/pwmchip0/pwm%d/period", device_no);
    fd = open(path, O_RDWR);
    if (fd < 0)
    {
        printf("pwm dev %d period file open failed.\n", device_no);
        return -1;
    }

    sprintf(str, "%lld", period_ns);
    ret = write(fd, str, strlen(str));
    if (ret < 0)
    {
        printf("pwm %d set period_ns failed.\n", device_no);
        close(fd);
        return -1;
    }
    close(fd);

    /*
    *set pwn duty_cycle
    */
    memset(path, 0, 64);
    sprintf(path, "/sys/class/pwm/pwmchip0/pwm%d/duty_cycle", device_no);
    fd = open(path, O_RDWR);
    if (fd < 0)
    {
        printf("pwm dev %d duty file open failed.\n", device_no);
        return -1;
    }

    memset(str, 0, 32);
    sprintf(str, "%lld", duty_ns);
    ret = write(fd, str, strlen(str));
    if (ret < 0)
    {
        printf("pwm dev %d set duty_ns failed.\n", device_no);
        close(fd);
        return -1;
    }
    close(fd);

    /*
    *enable pwm after set pwm period and duty_cycle
    */
    memset(path, 0, 64);
    sprintf(path, "/sys/class/pwm/pwmchip0/pwm%d/enable", device_no);
    fd = open(path, O_RDWR);
    if (fd < 0)
    {
        printf("pwm dev %d enable file open failed.\n", device_no);
        return -1;
    }

    ret = write(fd, "1", strlen("1"));
    if (ret < 0)
    {
        printf("pwm dev %d set enable failed.\n", device_no);
        close(fd);
        return -1;
    }
    close(fd);

    return 0;
}

int SdkPwm_Close(int device_no)
{
    int fd = -1;
    int ret = 0;
    char pwm_name[8] = {0};
    char path[64] = {0};
    char dev_name[64] = {0};
    char str[32] = {0};

    sprintf(path, "/sys/class/pwm/pwmchip0/pwm%d", device_no);
    if (access(path, F_OK))
    {
        printf("pwm dev %d not open.\n", device_no);
        return -1;
    }

    /*
    *disable pwm before close
    */
    memset(path, 0, 64);
    sprintf(path, "/sys/class/pwm/pwmchip0/pwm%d/enable", device_no);
    fd = open(path, O_RDWR);
    if (fd < 0)
    {
        printf("pwm dev %d enable file open failed.\n", device_no);
        return -1;
    }

    ret = write(fd, "0", strlen("0"));
    if (ret < 0)
    {
        printf("pwm dev %d set disable failed.\n", device_no);
        close(fd);
        return -1;
    }
    close(fd);

    /*
    *set pwn period
    */
    memset(path, 0, 64);
    sprintf(path, "/sys/class/pwm/pwmchip0/pwm%d/period", device_no);
    fd = open(path, O_RDWR);
    if (fd < 0) {
        printf("pwm dev %d period file open failed.\n", device_no);
        return -1;
    }

    ret = write(fd, "0", strlen("0"));
    if (ret < 0)
    {
        printf("pwm dev %d set period_ns failed.\n", device_no);
        close(fd);
        return -1;
    }
    close(fd);

    /*
    *set pwn duty_cycle
    */
    memset(path, 0, 64);
    sprintf(path, "/sys/class/pwm/pwmchip0/pwm%d/duty_cycle", device_no);
    fd = open(path, O_RDWR);
    if (fd < 0)
    {
        printf("pwm dev %d duty file open failed.\n", device_no);
        return -1;
    }

    memset(str, 0, 32);
    sprintf(str, "%d", 0);
    ret = write(fd, str, strlen(str));
    if (ret < 0)
    {
        printf("pwm dev %d set duty_ns failed.\n", device_no);
        close(fd);
        return -1;
    }

    /*
    *close pwm dev
    */
    sprintf(dev_name, "/sys/class/pwm/pwmchip0/unexport");
    fd = open(dev_name, O_WRONLY);
    if (fd < 0)
    {
        printf("Open pwm dev unexport %d fail\n", device_no);
        return -1;
    }

    /*
    *write 0 to unexport, it will close pwm dev.
    */
    sprintf(pwm_name, "%d",device_no);
    ret = write(fd, pwm_name, strlen(pwm_name));
    if (ret < 0)
    {
        close(fd);
        printf("close pwm %d fail\n", device_no);
        return -1;
    }
    close(fd);

    return 0;
}

void Ext_SdkPwm_Init(int num)
{
    int ret;

    SdkPwm_Close(num);
    ret = SdkPwm_Open(num);
    if (ret)
    {
        printf("open pwm device fail.\n");
        return;
    }
}

void Ext_SdkPwm_Destroy(int num)
{
    SdkPwm_Close(num);
}

void Ext_SdkPwm_Set_Gradual_Change(int num,long long duty_ns,long long period_ns)
{
    long long i = 0;
    int ret;

    if(g_ChipSdk_Class_Pwm_Period == period_ns)
    {
        return;
    }

    if(g_ChipSdk_Class_Pwm_Period > period_ns)
    {
        for(i = g_ChipSdk_Class_Pwm_Period; i > period_ns;i -= DEF_PWM_PERIOD_STEP_SIZE)
        {
            ret = SdkPwm_Set(num, duty_ns, i);
            if (ret)
            {
                printf("set pwm device fail.\n");
                return;
            }

            if(i >= DEF_PWM_PERIOD_LOW_BRIGHTNESS)
            {
                usleep(10 * 1000);
            }
            else
            {
                usleep(80 * 1000);
            }
        }
    }
    else
    {
        for(i = (g_ChipSdk_Class_Pwm_Period + DEF_PWM_PERIOD_STEP_SIZE); i < period_ns;i += DEF_PWM_PERIOD_STEP_SIZE)
        {
            ret = SdkPwm_Set(num, duty_ns, i);
            if (ret)
            {
                printf("set pwm device fail.\n");
                return;
            }
            usleep(30 * 1000);
        }
    }
    g_ChipSdk_Class_Pwm_Period = period_ns;
}

void Ext_SdkPwm_Set(int num,long long duty_ns,long long period_ns)
{
    int ret;

    g_ChipSdk_Class_Pwm_Period = period_ns;
    ret = SdkPwm_Set(num, duty_ns, period_ns);
    if (ret)
    {
        printf("set pwm device fail.\n");
        return;
    }
}
